using System;
using System.Collections.Generic;



namespace Framework
{
    public abstract class BaseEntity : BaseComponent
    {
        public int Id { get; protected set; }

        public Dictionary<Type, BaseComponent> m_Type2Component = new Dictionary<Type, BaseComponent>();
        public List<BaseComponent> m_UpdateComponents = new List<BaseComponent>();

        public static T CreateEntity<T>() where T : BaseEntity
        {
            return CreateComponent<T>();
        }

        public T AddComponent<T>() where T : BaseComponent
        {
            Type type = typeof(T);
            if (this.m_Type2Component.ContainsKey(type))
            {
                throw new Exception($"AddComponent, component already exist, id: {this.Id}, component: {typeof(T).Name}");
            }
            T component = CreateComponent<T>();
            component.Parent = this;
            this.m_Type2Component.Add(type, component);
            if (component.NeedUpdate)
            {
                this.m_UpdateComponents.Add(component);
            }
            return component;
        }

        public void RemoveComponent<T>() where T : BaseComponent
        {
            if (this.IsDisposed)
            {
                return;
            }
            Type type = typeof(T);
            BaseComponent component;
            if (!this.m_Type2Component.TryGetValue(type, out component))
            {
                return;
            }
            this.m_UpdateComponents.Remove(component);
            this.m_Type2Component.Remove(type);
            component.Dispose();
        }

        public T GetComponent<T>() where T : BaseComponent
        {
            Type type = typeof(T);
            BaseComponent component;
            if (!this.m_Type2Component.TryGetValue(type, out component))
            {
                return null;
            }
            return component as T;
        }

        public T GenComponent<T>() where T : BaseComponent
        {
            Type type = typeof(T);
            BaseComponent component;
            if (!this.m_Type2Component.TryGetValue(type, out component))
            {
                return this.AddComponent<T>();
            }
            return component as T;
        }

        public override void Update(float elapseSeconds, float realElapseSeconds)
        {
            int count = this.m_UpdateComponents.Count;
            for (int i = 0; i < count; i++)
            {
                BaseComponent component = this.m_UpdateComponents[i];
                component.Update(elapseSeconds, realElapseSeconds);
            }
        }

        public override void Dispose()
        {
            if (this.IsDisposed)
            {
                return;
            }
            foreach (BaseComponent component in this.m_Type2Component.Values)
            {
                try
                {
                    component.Dispose();
                }
                catch (Exception e)
                {
                    Log.Error(e);
                }
            }
            this.m_Type2Component.Clear();
            this.m_UpdateComponents.Clear();
            base.Dispose();
        }
    }
}